package com.wiscamp.ninechapters.ddd;

import com.wiscamp.ninechapters.common.core.CollectionHelper;
import com.wiscamp.ninechapters.common.rest.PagedEntity;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.function.*;

public class AppServiceHelper {

    public static <E, V> V getById(@Min(0) long id, LongFunction<E> getFunction, Function<E, V> toVOFunction) {
        var entity = getFunction.apply(id);
        if (entity != null)
            return toVOFunction.apply(entity);
        return null;
    }

    public static <E, V> V getByText(@NotBlank String text, Function<String, E> getFunction, Function<E, V> toVOFunction) {
        var entity = getFunction.apply(text);
        if (entity != null)
            return toVOFunction.apply(entity);
        return null;
    }

    public static <E, V> V getByTextAndId(@NotBlank String text, @Min(0) long id, BiFunction<String, Long, E> getFunction, Function<E, V> toVOFunction) {
        var entity = getFunction.apply(text, id);
        if (entity != null)
            return toVOFunction.apply(entity);
        return null;
    }

    public static <E, V> V getByIdAndId(@Min(0) long id1, @Min(0) long id2, BiFunction<Long, Long, E> getFunction, Function<E, V> toVOFunction) {
        var entity = getFunction.apply(id1, id2);
        if (entity != null)
            return toVOFunction.apply(entity);
        return null;
    }

    public static <E, V> Collection<V> getAll(Supplier<Collection<E>> supplier, Function<E, V> toVOFunction) {
        var entities = supplier.get();
        if (!CollectionUtils.isEmpty(entities)) {
            return CollectionHelper.convertToArrayList(entities, toVOFunction);
        }
        return new ArrayList<>();
    }

    public static <E, V> Collection<V> getListById(@Min(0) long id, LongFunction<Collection<E>> getFunction, Function<E, V> toVOFunction) {
        var entities = getFunction.apply(id);
        if (!CollectionUtils.isEmpty(entities)) {
            return CollectionHelper.convertToArrayList(entities, toVOFunction);
        }
        return new ArrayList<>();
    }

    public static <E, V> Collection<V> getListByText(@NotBlank String text, Function<String, Collection<E>> getFunction, Function<E, V> toVOFunction) {
        var entities = getFunction.apply(text);
        if (!CollectionUtils.isEmpty(entities)) {
            return CollectionHelper.convertToArrayList(entities, toVOFunction);
        }
        return new ArrayList<>();
    }

    public static <E, V> Collection<V> getListByTextAndId(@NotBlank String text, @Min(0) long id, BiFunction<String, Long, Collection<E>> getFunction, Function<E, V> toVOFunction) {
        var entities = getFunction.apply(text, id);
        if (!CollectionUtils.isEmpty(entities)) {
            return CollectionHelper.convertToArrayList(entities, toVOFunction);
        }
        return new ArrayList<>();
    }

    public static <E, V> Collection<V> getListByIdAndId(@Min(0) long id1, @Min(0) long id2, BiFunction<Long, Long, Collection<E>> getFunction, Function<E, V> toVOFunction) {
        var entities = getFunction.apply(id1, id2);
        if (!CollectionUtils.isEmpty(entities)) {
            return CollectionHelper.convertToArrayList(entities, toVOFunction);
        }
        return new ArrayList<>();
    }

    public static <E, V> Collection<V> getListByIds(@NotBlank Collection<Long> ids, Function<Collection<Long>, Collection<E>> getFunction, Function<E, V> toVOFunction) {
        var entities = getFunction.apply(ids);
        if (!CollectionUtils.isEmpty(entities)) {
            return CollectionHelper.convertToArrayList(entities, toVOFunction);
        }
        return new ArrayList<>();
    }

    public static <E, V> V enable(@Min(0) long id, Function<Long, E> enableFunction, Function<E, V> toVOFunction) {
        var entity = enableFunction.apply(id);
        if (entity != null)
            return toVOFunction.apply(entity);
        return null;
    }

    public static <E, V> V disable(@Min(0) long id, Function<Long, E> disableFunction, Function<E, V> toVOFunction) {
        var entity = disableFunction.apply(id);
        if (entity != null)
            return toVOFunction.apply(entity);
        return null;
    }

    public static boolean delete(@Min(0) long id, Function<Long, Boolean> deleteFunction) {
        return deleteFunction.apply(id);
    }

    public static <C, E, V> V createOrUpdate(C command, UnaryOperator<E> saveFunction, Function<E, V> toVOFunction, Function<C, E> toEntityFunction) {
        var entity = toEntityFunction.apply(command);
        if (entity != null) {
            var savedEntity = saveFunction.apply(entity);
            return toVOFunction.apply(savedEntity);
        }
        return null;
    }

    public static <T1, T2> PagedEntity<T2> convertPagedEntity(PagedEntity<T1> source, Function<T1, T2> function) {
        var target = new PagedEntity<T2>();
        target.setField(source.getField());
        target.setSort(source.getSort());
        target.setTotal(source.getTotal());
        target.setPages(source.getPages());
        var targetList = CollectionHelper.convertToArrayList(source.getEntities(), function);
        target.setEntities(targetList);
        return target;
    }

    public static <T1, T2> PagedEntities<T2> convertPagedEntities(PagedEntities<T1> source, Function<T1, T2> function) {
        var targetList = CollectionHelper.convertToArrayList(source.getEntities(), function);
        var target = new PagedEntities<T2>(source.getTotalCount(), source.getPageSize(), targetList, source.getPage(), source.getSortDirection(), source.getSortProperty());
        return target;
    }
}
